package com.study.servlet;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import javax.annotation.PostConstruct;
import javax.servlet.AsyncContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @Author tanglingyu
 * @Date: 2021/10/12/ 15:56
 * @Description
 */
public class MyServlet extends HttpServlet {

  /**
   * Servlet 3.0 之前，
   * 一个普通 Servlet 的主要工作流程大致如下：
   * 首先，Servlet 接收到请求之后，可能需要对请求携带的数据进行一些预处理；
   * 接着，调用业务接口的某些方法，以完成业务处理；最后，根据处理的结果提交响应，Servlet 线程结束。
   * 其中第二步的业务处理通常是最耗时的，这主要体现在数据库操作，以及其它的跨网络调用等，在此过程中，
   * Servlet 线程一直处于阻塞状态，直到业务方法执行完毕。
   *
   * Servlet 3.0
   * 针对这个问题做了开创性的工作，现在通过使用 Servlet 3.0 的异步处理支持
   * ，之前的 Servlet 处理流程可以调整为如下的过程：
   * 首先，Servlet 接收到请求之后，可能首先需要对请求携带的数据进行一些预处理；
   * 接着，Servlet 线程将请求转交给一个异步线程来执行业务处理，线程本身返回至容器，
   * 此时 Servlet 还没有生成响应数据，异步线程处理完业务以后，
   * 可以直接生成响应数据（异步线程拥有 ServletRequest 和 ServletResponse 对象的引用），
   * 或者将请求继续转发给其它 Servlet。如此一来，
   * Servlet 线程不再是一直处于阻塞状态以等待业务逻辑的处理，而是启动异步线程之后可以立即返回。
   * @param req
   * @param resp
   * @throws ServletException
   * @throws IOException
   */


  @Override
  protected void service(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException, IOException {
    System.out.println("do service...");
    super.service(req, resp);
  }

  @Override
  protected void doGet(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException, IOException {
    resp.setContentType("text/html;charset=UTF-8");
    PrintWriter out = resp.getWriter();
    out.println("进入Servlet的时间：" + new Date() + ".");
    out.flush();
    AsyncContext ctx = req.startAsync();
    new Thread(new Executor(ctx)).start();
    out.println("结束Servlet的时间：" + new Date() + ".");
    out.flush();
  }

  @Override
  public void destroy() {
    System.out.println("destroy...");
    super.destroy();
  }

  @Override
  public void init() throws ServletException {
    System.out.println("init");
    super.init();
  }

  public MyServlet(){
    System.out.println("构造函数...");
  }

  //构造-->@PostConstruct-->init
  @PostConstruct
  public void test() {
    System.out.println("servlet postConstruct...");
  }



  public class Executor implements Runnable {

    private AsyncContext ctx = null;

    public Executor(AsyncContext ctx) {
      this.ctx = ctx;
    }

    public void run() {
      try {
        //等待十秒钟,以模拟业务方法的执行
        Thread.sleep(10000);
        PrintWriter out = ctx.getResponse().getWriter();
        out.println("业务处理完毕的时间：" + new Date() + ".");
        out.flush();
        ctx.complete();
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  }
}
